/*
* $Id: Controls.cpp 40 2010-02-25 12:59:54Z volok-aleksej@yandex.ru $
*
* Copyright 2008 by Volokitin Alexey
* All rights reserved
*
*/
#include "Common/include.h"
#include "Controls.h"
#include "Settings/DinIntDefined.h"
#include "Factories.h"
#include "Settings/Journal/ListBoxStateParser.h"

/******************************************************************************************************************/
/*                                                CStaticControl                                                  */
/******************************************************************************************************************/
CStaticControl::CStaticControl(const std::tstring& strId, const std::tstring& strState, const std::vector<Parameter>& aParameters)
: CControl(strId, strState, aParameters){
	tooltip.Create(this);
}
CStaticControl::~CStaticControl(){
	DestroyWindow();
}

void CStaticControl::CreateControl(int x, int y, int cx, int cy, int nStyle, const std::tstring& strCaption, CWnd* pParent, int nId){
	m_nStyle = nStyle;
	for(std::vector<Parameter>::iterator it = m_aParameters.begin(); it != m_aParameters.end(); it++){
		if(it->GetName() == TYPE){
			m_strType = it->GetValue();
			break;
		}
	}
	Create(strCaption.c_str(), WS_CHILD | WS_VISIBLE | SS_OWNERDRAW, CRect(CPoint(x, y), CSize(cx, cy)), pParent, nId);
	SetFont(m_pFont, TRUE);
	SetState(m_strState);
}
void CStaticControl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct){
	int nType = DSS_NORMAL;
	CFont* pFont = NULL;
	HGDIOBJ fontOld;
	if(m_strType == HEADER){
		CPen pen;
		pen.CreatePen(PS_SOLID, 1, RGB(150, 150, 150));
		CBrush brush;
		brush.CreateSolidBrush(CCommonFunction::GetBeeColor());
		HGDIOBJ penOld = SelectObject(lpDrawItemStruct->hDC, pen);
		HGDIOBJ brushOld = SelectObject(lpDrawItemStruct->hDC, brush);
		Rectangle(lpDrawItemStruct->hDC, lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.top,
					lpDrawItemStruct->rcItem.right, lpDrawItemStruct->rcItem.bottom);
		SelectObject(lpDrawItemStruct->hDC, brushOld);
		SelectObject(lpDrawItemStruct->hDC, penOld);
		nType |= (DT_SINGLELINE|DT_VCENTER);
		pFont = CCommonFunction::GetFont(_T("MS Sans Serif"), 16, TRUE, FALSE);
		fontOld = SelectObject(lpDrawItemStruct->hDC, pFont->m_hObject);
	}
	if(m_strType == HEADER_1){
		pFont = CCommonFunction::GetFont(_T("MS Sans Serif"), 14, TRUE, FALSE);
		fontOld = SelectObject(lpDrawItemStruct->hDC, pFont->m_hObject);
	}
	if((m_nStyle & SS_RIGHT) == SS_RIGHT)
		nType |= DT_RIGHT;
	else if((m_nStyle & SS_CENTER) == SS_CENTER)
		nType |= DT_CENTER;
	else
		nType = nType | DT_LEFT;
	SetBkMode(lpDrawItemStruct->hDC, TRANSPARENT);
	DrawText(lpDrawItemStruct->hDC, m_strState.c_str(), (int)m_strState.size(), &lpDrawItemStruct->rcItem, nType);
	if(pFont){
		SelectObject(lpDrawItemStruct->hDC, fontOld);
		delete pFont;
	}
}
void CStaticControl::SetState(const std::tstring& strState){
	SetWindowText(strState.c_str());
}

/******************************************************************************************************************/
/*                                                CButtonControl                                                  */
/******************************************************************************************************************/
CButtonControl::CButtonControl(const std::tstring& strId, const std::tstring& strState, const std::vector<Parameter>& aParameters )
: CControl(strId, strState, aParameters), m_bDownButton(FALSE){
	tooltip.Create(this);
}
CButtonControl::~CButtonControl(){
	DestroyWindow();
}

void CButtonControl::CreateControl(int x, int y, int cx, int cy, int nStyle, const std::tstring& strCaption, CWnd* pParent, int nId){
	Create(strCaption.c_str(), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | nStyle, CRect(CPoint(x, y), CSize(cx, cy)), pParent, nId);
	SetFont(m_pFont, TRUE);
	SetState(m_strState);
}

void CButtonControl::ApplyState(){
	if(m_strState == BUTTON_STATE_1){
		EnableWindow(TRUE);
		__super::SetState(TRUE);
	}
	else if(m_strState == BUTTON_STATE_2){
		EnableWindow(TRUE);
		__super::SetState(FALSE);
	}
	else if(m_strState == BUTTON_STATE_3){
		EnableWindow(FALSE);
		__super::SetState(FALSE);
	}
}

bool CButtonControl::IsTabStop(){
	return IsWindowEnabled();
}

void CButtonControl::TabStop(){
	SetFocus();
}

void CButtonControl::SetState( const std::tstring& strState ){
	__super::SetState(strState);
	ApplyState();
}

BEGIN_MESSAGE_MAP(CButtonControl, CCommonButton)
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()

void CButtonControl::OnMouseMove(UINT nFlags, CPoint point){
	if(m_bDownButton){
		CRect rect;
		GetClientRect(rect);
		if(point.x >= 0 && point.x <= rect.Width() && point.y >= 0 && point.y <= rect.Height()){
			m_strState = BUTTON_STATE_1;
			SendEvent();
		}
		else{
			m_strState = BUTTON_STATE_2;
			SendEvent();
		}
	}
	__super::OnMouseMove(nFlags, point);
}

void CButtonControl::OnLButtonDown(UINT nFlags, CPoint point){
	m_bDownButton = TRUE;
	m_strState = BUTTON_STATE_1;
	SendEvent();
	__super::OnLButtonDown(nFlags, point);
}

void CButtonControl::OnLButtonUp(UINT nFlags, CPoint point){
	m_bDownButton = FALSE;
	if(m_strState == BUTTON_STATE_1){
		m_strState = BUTTON_STATE_2;
		SendEvent();
	}
	__super::OnLButtonDown(nFlags, point);
}

/******************************************************************************************************************/
/*                                              CCheckBoxControl                                                  */
/******************************************************************************************************************/
CCheckBoxControl::CCheckBoxControl(const std::tstring& strId, const std::tstring& strState, const std::vector<Parameter>& aParameters)
: CControl(strId, strState, aParameters){
	tooltip.Create(this);
}
CCheckBoxControl::~CCheckBoxControl(){
	DestroyWindow();
}
void CCheckBoxControl::CreateControl(int x, int y, int cx, int cy, int nStyle, const std::tstring& strCaption, CWnd* pParent, int nId){
	Create(strCaption.c_str(), WS_CHILD | WS_VISIBLE | BS_CHECKBOX | BS_OWNERDRAW | nStyle, CRect(CPoint(x, y), CSize(cx, cy)), pParent, nId);
	SetFont(m_pFont, TRUE);
	__super::SetState(m_strState);
}
bool CCheckBoxControl::IsTabStop(){
	return IsWindowEnabled();
}
void CCheckBoxControl::TabStop(){
	SetFocus();
}
void CCheckBoxControl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct){
	UINT uStyle = DFCS_BUTTONCHECK;
	if(m_strState == CHECK_BOX_STATE_1)
		uStyle = DFCS_CHECKED;
	CBrush brush(GetSysColor(COLOR_BTNFACE));
	FillRect(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, brush);
	LOGFONT lgf;
	m_pFont->GetLogFont(&lgf);
	int y = (lpDrawItemStruct->rcItem.bottom - lgf.lfHeight)/2;
	CRect rect(0, y,  lgf.lfHeight, y + lgf.lfHeight);
	::DrawFrameControl(lpDrawItemStruct->hDC, &rect, DFC_BUTTON, uStyle);
	SetBkMode(lpDrawItemStruct->hDC, TRANSPARENT);
	rect = lpDrawItemStruct->rcItem;
	rect.left = lgf.lfHeight + 5;
	CString strText;
	GetWindowText(strText);
	DrawText(lpDrawItemStruct->hDC, strText.GetString(), strText.GetLength(), &rect, DT_SINGLELINE | DT_LEFT | DT_VCENTER);
}
void CCheckBoxControl::SetState(const std::tstring& strState){
	__super::SetState(strState);
	Invalidate(TRUE);
}

BEGIN_MESSAGE_MAP(CCheckBoxControl, CCommonButton)
	ON_WM_LBUTTONDOWN()
	ON_WM_KEYDOWN()
END_MESSAGE_MAP()

void CCheckBoxControl::OnLButtonDown(UINT nFlags, CPoint point){
	if(m_strState == CHECK_BOX_STATE_1)
		m_strState = CHECK_BOX_STATE_2;
	else
		m_strState = CHECK_BOX_STATE_1;
	SendEvent();
	__super::OnLButtonDown(nFlags, point);
}

void CCheckBoxControl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags){
	if(nChar == VK_SPACE){
		if(m_strState == CHECK_BOX_STATE_1)
			m_strState = CHECK_BOX_STATE_2;
		else
			m_strState = CHECK_BOX_STATE_1;
		SendEvent();
	}
	__super::OnKeyDown(nChar, nRepCnt, nFlags);
}

/******************************************************************************************************************/
/*                                                CEditControl                                                    */
/******************************************************************************************************************/
CEditControl::CEditControl(const std::tstring& strId, const std::tstring& strState, const std::vector<Parameter>& aParameters)
: CControl(strId, strState, aParameters){
	tooltip.Create(this);
	CreateParameters();
}
CEditControl::~CEditControl(){
	DestroyWindow();
	for(std::vector<IValidate*>::iterator it = m_aValidate.begin(); it != m_aValidate.end(); it++)
		(*it)->Free();
}
bool CEditControl::IsTabStop(){
	return IsWindowEnabled();
}
void CEditControl::CreateControl(int x, int y, int cx, int cy, int nStyle, const std::tstring& strCaption, CWnd* pParent, int nId){
	CreateEx(WS_EX_CLIENTEDGE, _T("EDIT"), strCaption.c_str(), WS_CHILD | WS_VISIBLE | nStyle, CRect(CPoint(x, y), CSize(cx, cy)), pParent, nId);
	SetWindowText(m_strState.c_str());
	SetFont(m_pFont, TRUE);
	SetState(m_strState);
}
void CEditControl::CreateParameters(){
	for (std::vector<Parameter>::iterator it = m_aParameters.begin(); it != m_aParameters.end(); it++){
		IValidate* pValidate = CValidateFactory::CreateValidate(it->GetName(), it->GetValue());
		if(pValidate)
			m_aValidate.push_back(pValidate);
	}
}
void CEditControl::TabStop(){
	SetFocus();
}

BEGIN_MESSAGE_MAP(CEditControl, CCommonEdit)
	ON_WM_CHAR()
	ON_WM_KEYDOWN()
END_MESSAGE_MAP()

void CEditControl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags){
	if(nChar == VK_BACK || nChar == VK_RETURN || nChar == VK_TAB){
		if(nChar != VK_TAB)
			__super::OnChar(nChar, nRepCnt, nFlags);
		CString str;
		GetWindowText(str);
		m_strState = str.GetString();
		SendEvent();
		return;
	}
	bool bValidation = TRUE;
	for (std::vector<IValidate*>::iterator it = m_aValidate.begin(); it != m_aValidate.end(); it++){
		bValidation = FALSE;
		CString str;
		GetWindowText(str);
		int nStart, nEnd;
		GetSel(nStart, nEnd);
		std::tstring stdStr(str.GetString());
		if(nStart != nEnd)
			stdStr.erase(stdStr.begin() + nStart, stdStr.begin() + nEnd);
		stdStr.insert(nStart, 1, (TCHAR)nChar);
		if((*it)->bValidate(stdStr.c_str())){
			m_strState = stdStr;
			__super::OnChar(nChar, nRepCnt, nFlags);
			SendEvent();
			break;
		}
	}
	if(bValidation){
		__super::OnChar(nChar, nRepCnt, nFlags);
		CString str;
		GetWindowText(str);
		m_strState = str.GetString();
		SendEvent();
	}
}
void CEditControl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags){
	__super::OnKeyDown(nChar, nRepCnt, nFlags);
	if(nChar == VK_DELETE){
		CString str;
		GetWindowText(str);
		m_strState = str.GetString();
		SendEvent();
	}
}
void CEditControl::SetState(const std::tstring& strState){
	SetWindowText(strState.c_str());
}

/******************************************************************************************************************/
/*                                                CEditNumberControl                                              */
/******************************************************************************************************************/
CEditNumberControl::CEditNumberControl(const std::tstring& strId, const std::tstring& strState, const std::vector<Parameter>& aParameters)
: CEditControl(strId, strState, aParameters){}
CEditNumberControl::~CEditNumberControl(){}

BOOL CEditNumberControl::PreCreateWindow(CREATESTRUCT& cs){
	cs.style = cs.style | ES_NUMBER;
	return TRUE;
}

BEGIN_MESSAGE_MAP(CEditNumberControl, CEditControl)
END_MESSAGE_MAP()

/******************************************************************************************************************/
/*                                                CEditDoubleControl                                              */
/******************************************************************************************************************/
CEditDoubleControl::CEditDoubleControl(const std::tstring& strId, const std::tstring& strState, const std::vector<Parameter>& aParameters)
: CEditControl(strId, strState, aParameters){}
CEditDoubleControl::~CEditDoubleControl(){}

BEGIN_MESSAGE_MAP(CEditDoubleControl, CEditControl)
	ON_WM_CHAR()
END_MESSAGE_MAP()

void CEditDoubleControl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags){
	CString str;
	GetWindowText(str);
	if(nChar == VK_BACK || nChar == VK_RETURN || nChar == VK_TAB)
		__super::OnChar(nChar, nRepCnt, nFlags);
	if(nChar == 0x16){
		OpenClipboard();
		HGLOBAL hglb = GetClipboardData(CF_TEXT);
		LPSTR  lptstrCopy = (LPSTR)GlobalLock(hglb);
		GlobalUnlock(hglb);
		for(int i = 0; i < (int)strlen(lptstrCopy); i++)
			SendMessage(WM_CHAR, lptstrCopy[i], 1);
		CloseClipboard();
		return;
	}
	if(str == _T("0") && nChar != '.'){
		SetWindowText(_T(""));
		str = _T("");
	}
	int nStart, nEnd;
	GetSel(nStart, nEnd);
	if(str.GetLength() >= 2 && str.GetAt(0) == '0' && str.GetAt(1) == '.' && nChar >= '1' && nChar <= '9' && nStart == 1){
		str.Delete(0, 1);
		SetWindowText(str);
	}
	std::tstring stdStr(str.GetString());
	if(nStart != nEnd)
		stdStr.erase(stdStr.begin() + nStart, stdStr.begin() + nEnd);
	stdStr.insert(nStart, 1,(TCHAR)nChar);
	size_t res = stdStr.find('.');
	if(	(nChar >= '0' && nChar <= '9' || nChar =='.') &&
		(stdStr.size() - res <= 3 && res != -1 && (stdStr[0] != '0' || stdStr[0] == '0' && (stdStr[1] == '.' || stdStr.size() == 1)) || res == -1) &&
		stdStr.find('.', res + 1) == -1)
		__super::OnChar(nChar, nRepCnt, nFlags);
}

/******************************************************************************************************************/
/*                                                CComboBoxControl                                                */
/******************************************************************************************************************/
CComboBoxControl::CComboBoxControl(const std::tstring& strId, const std::tstring& strState, const std::vector<Parameter>& aParameters)
: CControl(strId, strState, aParameters){
	tooltip.Create(this);
}
CComboBoxControl::~CComboBoxControl(){
	DestroyWindow();
}
void CComboBoxControl::CreateControl(int x, int y, int cx, int cy, int nStyle, const std::tstring& strCaption, CWnd* pParent, int nId){
	Create(WS_CHILD | WS_VISIBLE | nStyle, CRect(CPoint(x, y), CSize(cx, cy + 60)), pParent, nId);
	SetFont(m_pFont, TRUE);
	SetState(m_strState);
}
bool CComboBoxControl::IsTabStop(){
	return IsWindowEnabled();
}
void CComboBoxControl::TabStop(){
	SetFocus();
}

BEGIN_MESSAGE_MAP(CComboBoxControl, CCommonCombobox)
	ON_WM_CREATE()
END_MESSAGE_MAP()

int CComboBoxControl::OnCreate(LPCREATESTRUCT lpCreateStruct){
	int nRes = __super::OnCreate(lpCreateStruct);
	for(std::vector<Parameter>::const_iterator it = m_aParameters.begin(); it != m_aParameters.end(); it++){
		int nPos;
		if(it->GetName() == COMBO_STRING)
			nPos = AddString(it->GetValue().c_str());
		if(it->GetValue() == m_strState)
			SetCurSel(nPos);
	}
	return nRes;
}

BOOL CComboBoxControl::OnCommand(WPARAM wParam, LPARAM lParam){
	if(HIWORD(wParam) == EN_CHANGE){
		CString str;
		GetWindowText(str);
		m_strState = str.GetString();
		SendEvent();
	}else if(HIWORD(wParam) == CBN_SELCHANGE){
		CString str;
		GetLBText(GetCurSel(), str);
		m_strState = str.GetString();
		SendEvent();
	}
	return __super::OnCommand(wParam, lParam);
}
void CComboBoxControl::SetState(const std::tstring& strState){
	if((GetStyle()&CBS_DROPDOWNLIST) == CBS_DROPDOWNLIST)
		SetCurSel(FindString(-1, strState.c_str()));
	else
		SetWindowText(strState.c_str());
}

/******************************************************************************************************************/
/*                                                   CListBoxControl                                              */
/******************************************************************************************************************/
CListBoxControl::CListBoxControl(const std::tstring& strId, const std::tstring& strState, const std::vector<Parameter>& aParameters)
: CControl(strId, strState, aParameters){
	tooltip.Create(this);
}
CListBoxControl::~CListBoxControl(){
	DestroyWindow();
}
void CListBoxControl::CreateControl(int x, int y, int cx, int cy, int nStyle, const std::tstring& strCaption, CWnd* pParent, int nId){
	Create(WS_CHILD | WS_VISIBLE | nStyle, CRect(CPoint(x, y), CSize(cx, cy)), pParent, nId);
	SetFont(m_pFont, TRUE);
	if(m_strState.empty()){
		CListBoxStateParser stateParser(_T(""));
		for(std::vector<Parameter>::iterator it = m_aParameters.begin(); it != m_aParameters.end(); it++){
			if(it->GetName() == LIST_STRING){
				std::tstring strValue = it->GetValue();
				size_t nPos = strValue.find('|');
				stateParser.AddChange(std::tstring(strValue.begin(), strValue.begin() + nPos), _ttoi(strValue.c_str() + nPos + 1), _ADD);
			}
		}
		stateParser.SaveChange();
		SetState(stateParser.GetState());
		SendEvent();
	}
	else
		FillList();
}
bool CListBoxControl::IsTabStop(){
	return TRUE;
}
void CListBoxControl::TabStop(){
	SetFocus();
}
void CListBoxControl::SaveSel(int Pos){
	std::tstring strTemp;
	if(Pos != -1){
		CString str;
		GetText(Pos, str);
		strTemp = str.GetString();
	}
	CListBoxStateParser stateParser(m_strState);
	stateParser.SetCurSel(strTemp);
	m_strState = stateParser.GetState();
}
void CListBoxControl::SetState(const std::tstring& strState){
	__super::SetState(strState);
	FillList();
}
void CListBoxControl::FillList(){
	ResetContent();
	CListBoxStateParser stateParser(m_strState);
	std::tstring strState = stateParser.GetCurSel();
	std::vector<CUserFieldsTable::content> aAddColumns = stateParser.GetAllColumns();
	for (std::vector<CUserFieldsTable::content>::iterator it = aAddColumns.begin(); it != aAddColumns.end(); it++){
		int pos = __super::AddString(it->s_strName.c_str());
		SetItemData(pos, it->s_type);
		if((*it).s_strName == strState)
			SetCurSel(pos);
	}
}
void CListBoxControl::AddString(const std::tstring& strValue, int nType, const std::tstring& strState){
	int Pos = __super::AddString(strValue.c_str());
	SetItemData(Pos, nType);
	if(strValue == strState)
		SetCurSel(Pos);
}

BEGIN_MESSAGE_MAP(CListBoxControl, CCommonListBox)
	ON_WM_KEYDOWN()
	ON_WM_LBUTTONDOWN()
	ON_WM_RBUTTONDOWN()
END_MESSAGE_MAP()

void CListBoxControl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags){
	__super::OnKeyDown(nChar, nRepCnt, nFlags);
	if(nChar == VK_DOWN || nChar == VK_UP){
		int nPos = GetCurSel();
		SaveSel(nPos);
		SendEvent();
	}
}

void CListBoxControl::OnLButtonDown(UINT nFlags, CPoint point){
	BOOL bOutside;
	int Pos = ItemFromPoint(point, bOutside);
	if(bOutside)
		Pos = -1;
	SetCurSel(Pos);
	SaveSel(Pos);
	SendEvent();
	__super::OnLButtonDown(nFlags, point);
}

void CListBoxControl::OnRButtonDown(UINT nFlags, CPoint point){
	BOOL bOutside;
	int Pos = ItemFromPoint(point, bOutside);
	if(bOutside)
		Pos = -1;
	SetCurSel(Pos);
	SaveSel(Pos);
	SendEvent();
	__super::OnRButtonDown(nFlags, point);
}

/******************************************************************************************************************/
/*                                              CDateTimeControl                                                  */
/******************************************************************************************************************/
CDateTimeControl::CDateTimeControl( const std::tstring& strId, const std::tstring& strState, const std::vector<Parameter>& aParameters )
: CControl(strId, strState, aParameters){
	tooltip.Create(this);
}
CDateTimeControl::~CDateTimeControl(){
	DestroyWindow();
}
bool CDateTimeControl::IsTabStop(){
	return true;
}
void CDateTimeControl::TabStop(){
	SetFocus();
}
void CDateTimeControl::SetState(const std::tstring& strState){
//	if(strState.empty()){
//		CTime time;
//		GetTime(time);
//		__super::SetState(time.Format(_T("%d.%m.%Y")).GetString());
//	}else
//		__super::SetState(strState);
//	CTime time(CCommonFunction::GetTime(strState));
//	SetTime(&time);
}
void CDateTimeControl::CreateControl(int x, int y, int cx, int cy, int nStyle, const std::tstring& strCaption, CWnd* pParent, int nId){
	Create(WS_VISIBLE | WS_CHILD | WS_TABSTOP | nStyle, CRect(CPoint(x, y), CSize(cx, cy)), pParent, nId);
	SetState(m_strState);
	SendEvent();
}

BEGIN_MESSAGE_MAP(CDateTimeControl, CCommonDateTimeCtrl)
	ON_WM_KEYUP()
END_MESSAGE_MAP()

BOOL CDateTimeControl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult){
	LPNMHDR pNmhdr = (LPNMHDR)lParam;
	if(pNmhdr->code == MCN_SELCHANGE){
		CTime time;
		GetTime(time);
		m_strState = time.Format(_T("%d.%m.%Y")).GetString();
		SendEvent();
	}
	return __super::OnNotify(wParam, lParam, pResult);
}

void CDateTimeControl::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags){
	__super::OnKeyUp(nChar, nRepCnt, nFlags);
	CTime time;
	GetTime(time);
	m_strState = time.Format(_T("%d.%m.%Y")).GetString();
	SendEvent();
}